/**
 *
 */
package info.touret.winecellar.bottle.server.domain;

import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;
import info.touret.winecellar.dao.server.DAOException;
import info.touret.winecellar.dao.server.DataStoreObject;
import info.touret.winecellar.producer.server.domain.Producer;
import info.touret.winecellar.reminder.ReminderQueueServlet.PARAMETERS;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

import javax.persistence.Basic;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.Future;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Past;

import org.apache.log4j.Logger;

import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions.Method;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;

/**
 * @author touret-a
 */
@com.googlecode.objectify.annotation.Entity
public class Bottle extends DataStoreObject<Bottle> implements Serializable {

	/**
     *
     */
	private static final long serialVersionUID = 1L;

	/**
     *
     */
	public Bottle() {
		super();
	}

	@NotNull
	private String name;

	private Key<Producer> producer;

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name
	 *            the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	private Key<Tag>[] tags;

	public Key<Tag>[] getTags() {
		return tags;
	}

	public void setTags(Key<Tag>[] tags) {
		this.tags = tags;
	}

	@Basic
	@Min(1900)
	private Integer vintage;
	@Basic
	private String denomination;
	@Basic
	@Min(0)
	private Long quantity;

	@Temporal(TemporalType.DATE)
	@Future
	private Date toDrink;
	@Temporal(TemporalType.DATE)
	private Date acquired;

	@Past
	public Date getAcquired() {
		return acquired;
	}

	public void setAcquired(Date acquired) {
		this.acquired = acquired;
	}

	public String getDenomination() {
		return denomination;
	}

	public void setDenomination(String denomination) {
		this.denomination = denomination;
	}

	public Long getQuantity() {
		return quantity;
	}

	public void setQuantity(Long quantity) {
		this.quantity = quantity;
	}

	public Date getToDrink() {
		return toDrink;
	}

	public void setToDrink(Date toDrink) {
		this.toDrink = toDrink;
	}

	public Integer getVintage() {
		return vintage;
	}

	public void setVintage(Integer vintage) {
		this.vintage = vintage;
	}

	public Bottle(String name, Producer producer, Key<Tag>[] tags,
			Integer vintage, String denomination, Long quantity, Date toDrink,
			Date acquired) {
		this.name = name;
		this.producer = new com.googlecode.objectify.Key<Producer>(
				Producer.class, producer.getId());

		this.tags = tags;
		this.vintage = vintage;
		this.denomination = denomination;
		this.quantity = quantity;
		this.toDrink = toDrink;
		this.acquired = acquired;
	}

	public com.googlecode.objectify.Key<Producer> getProducer() {
		return producer;
	}

	public void setProducer(com.googlecode.objectify.Key<Producer> producer) {
		this.producer = producer;
	}

	private String producerLabel;

	public void setProducerLabel(String producerValue) {
		this.producerLabel = producerValue;
	}

	/**
	 * @return le libelle du producteur
	 */
	public String getProducerLabel() {
		if (producerLabel == null) {
			setProducerLabel(new String());
		}
		return producerLabel;
	}

	/**
	 * @return la liste des bouteilles appartenant a l utilisateur courant
	 */
	public static List<Bottle> findAllBottles() {
		Objectify objectify = ObjectifyService.begin();
		List<Bottle> bottles = objectify.query(Bottle.class)
				.filter("userID", retreiveCurrentUserID()).list();
		trace.info("Bottles :" + bottles + " recuperees");
		bottles.size();
		trace.info("# Bottles :" + bottles.size());
		for (Bottle bottle : bottles) {
			if (bottle.getProducer() != null) {
				bottle.setProducerLabel(objectify.get(bottle.getProducer())
						.getName());
			}
		}
		return bottles;
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see info.touret.winecellar.dao.server.DataStoreObject#persist()
	 */
	public void persist() {
		try {
			Objectify objectify = ObjectifyService.begin();
			// logiquement il n y a pas besoin de ce test
			if (getProducerID() != null) {
				setProducer(new Key<Producer>(Producer.class, getProducerID()));
			}
			setUserID(retreiveCurrentUserID());
			objectify.put(this);
			Queue queue = QueueFactory.getQueue("reminder-queue");
			queue.add(withUrl("/tasks/reminderqueueservlet")
					.param(PARAMETERS.USERID.toString(), getUserID().toString())
					.param(PARAMETERS.BOTTLEID.toString(), getId().toString())
					.method(Method.POST));
		} catch (Exception e) {
			trace.error(
					"Erreur lors de l insertion de l objet " + this.toString(),
					e);
			throw new DAOException(e);
		}
	}

	private static final Logger trace = Logger.getLogger(Bottle.class
			.getCanonicalName());

	/**
	 * @param id
	 *            l identifiant (Key)
	 * @return la bouteille correspondante
	 */
	public static Bottle findBottle(Long id) {
		Objectify objectify = ObjectifyService.begin();
		return objectify.find(Bottle.class, id);
	}

	private Long producerID;

	public Long getProducerID() {
		return producerID;
	}

	public void setProducerID(Long producerID) {
		this.producerID = producerID;
	}

	/**
	 * @param criteria
	 *            pour l instant le seul critere est le nom
	 * @return la liste des bouteilles correspondantes
	 */
	public static List<Bottle> findBottlesByCriteria(String criteria) {
		List<Bottle> bottles = new ArrayList<Bottle>();
		Objectify objectify = ObjectifyService.begin();
		List<Bottle> allbottles = objectify.query(Bottle.class)
				.filter("userID", retreiveCurrentUserID()).list();
		Pattern pattern = Pattern.compile(".*" + criteria + ".*");
		for (Bottle current : allbottles) {
			if (pattern.matcher(current.getName()).find()
					|| pattern.matcher(current.getName()).find()
					|| pattern.matcher(current.getDenomination()).find()) {
				bottles.add(current);
			}
		}

		return bottles;
	}

}
